#include "iniParse.h"

const char *tips[] = {
    "This tool is only used to parse ini  files, and is very basic, for reference only\n",
    "Usage is as follows: *.exe *.ini \n"};

int8_t lineParse(uint8_t *lineData, uint32_t dataLen, OtaInfo_t *result)
{

    uint8_t *data = NULL, type = LINE_PARSE_TYPE_ITEM;
    uint32_t dataIndex = 0, equitIndex = 0;
    data = (uint8_t *)malloc(dataLen);
    if (data == NULL)
    {
        printf("malloc failed\n");
        return -1;
    }

    memset(data, 0x00, dataLen);

    // 去除注释内容,截取有效内容
    for (int i = 0; i < dataLen; i++)
    {
        // printf("%c ", lineData[i]);
        if (lineData[i] == ' ')
        {
            continue;
        }
        else if (lineData[i] == '#')
        {
            // 这一行所有有效数据获取完毕
            // printf("lineData len %d\n", dataIndex);
            if (dataIndex > 0)
            {
                // printf("break %s\n", lineData);
                break;
            }
            else
            {
                // printf("return %s\n", lineData);
                return 0;
            }
        }
        else if (lineData[i] == '[')
        {
            type = LINE_PARSE_TYPE_TITLE;
            continue;
        }

        data[dataIndex] = lineData[i];
        dataIndex++;
    }

    // 取得组名
    if (type == LINE_PARSE_TYPE_TITLE)
    {
        // 解析标题
        memcpy(result->groupName, data + 1, dataIndex - 2);

        // 释放资源
        if (data != NULL)
        {
            free(data);
            data = NULL;
        }

        return 0;
    }

    // 找到 = 位置
    for (int i = 0; i < dataIndex; i++)
    {
        if (data[i] == '=')
        {
            equitIndex = i;
            break;
        }
    }

    if (equitIndex <= 0 || (dataIndex - equitIndex - 1) <= 0)
    {

        // 释放资源
        if (data != NULL)
        {
            free(data);
            data = NULL;
        }

        return -1;
    }

    // printf("equitIndex %d\n", equitIndex);
    memcpy(result->itemName, data, equitIndex);
    memcpy(result->itemData, &data[equitIndex + 1], (dataIndex - equitIndex - 1));

    // 释放资源
    if (data != NULL)
    {
        free(data);
        data = NULL;
    }

    return 0;
}
int8_t getDataLineCount(uint8_t *fileData, uint32_t fileSize, int32_t *parseLen)
{
    // 找打文件换行符
    uint8_t newLine[] = {0x0d, 0x0a};
    uint8_t lineCount = 0,
            lineIndex[MAX_LINE] = {0};

    // printf("%#x -> %#x %#x\n", fileData[i], newLine[0], newLine[1]);

    // 获取所有行号
    for (int i = 0; i < fileSize; i++)
    {
        if (memcmp(&fileData[i], newLine, 2) == 0)
        {
            // printf("newLine index %d\n", i);

            lineIndex[lineCount] = i;
            lineCount++;

            // 保留最后一次的行号，记录下对当前内容解析的最后一段
            *parseLen = i;
        }
    }

    // 特殊情况下，ini 文件最后一行没有换行符，需要单独处理
    if (lineCount == 0 && fileSize != 0)
    {
        lineIndex[0] = fileSize;
        lineCount = 1;
        *parseLen = 0;
    }

    // 输出行号index
    // printf("\n lineIndex ");
    // for (int i = 0; i < lineCount; i++)
    // {
    //     printf("%d ", lineIndex[i]);
    // }
    // printf("\n");

    // 判断行数是否超过最大值, 超过则退出
    if (lineCount > MAX_LINE)
    {
        printf("lineCount %d MAX!!!!\n", lineCount);
        return -1;
    }

    OtaInfo_t tempOtaInfo[MAX_LINE] = {0};

    // 解析每一行
    uint8_t *lineData = NULL, index = 0;

    for (int i = 0; i < lineCount; i++)
    {
        uint8_t dataLen = 0, dataIndex = 0;

        // 准备新的数据
        if (i == 0)
        {
            dataLen = lineIndex[i];
            dataIndex = 0;
        }
        else
        {
            dataLen = lineIndex[i] - lineIndex[i - 1] - 2;
            dataIndex = lineIndex[i] - dataLen;
        }

        // 释放旧的数据
        if (lineData != NULL)
        {
            free(lineData);
            lineData = NULL;
        }

        lineData = (uint8_t *)malloc(dataLen);

        if (lineData == NULL)
        {
            printf("malloc failed\n");
            return -1;
        }

        // 拷贝数据
        if (dataLen <= 0)
        {
            // printf("dataLen %d, dataIndex %d\n", dataLen, dataIndex);
            continue;
        }
        memcpy(lineData, &fileData[dataIndex], dataLen);
        // printf("lineData %c \n", lineData[0]);
        // continue;

        // printf("lineData [%s] dataLen [%d]\n", lineData, dataLen);
        if (lineParse(lineData, dataLen, &tempOtaInfo[index]) == 0)
        {
            if (strlen(tempOtaInfo[index].groupName) != 0 ||
                strlen(tempOtaInfo[index].itemName) != 0 ||
                strlen(tempOtaInfo[index].itemData) != 0)
            {
                printf("[%d]--> groupName [%s] itemName [%s], itemData [%s]\n", index, tempOtaInfo[index].groupName, tempOtaInfo[index].itemName, tempOtaInfo[index].itemData);

                if (strcmp(tempOtaInfo[index].itemName, "start_addr") == 0)
                {
                    int8_t *endPos = NULL;
                    uint32_t res = 0;
                    res = strtol(tempOtaInfo[index].itemData, &endPos, 16);

                    printf("******** start_addr [%#x]  endPos %c\n", res, endPos);
                }
                index++;
            }
        }
    }

    // 释放旧的数据
    if (lineData != NULL)
    {
        free(lineData);
        lineData = NULL;
    }

    return 0;
}

int8_t parseIni(char *path)
{
    FILE *fp = NULL;
    fp = fopen(path, "rb");
    printf("parseIni %s\n", path);

    if (fp == NULL)
    {
        printf("open file failed\n");
        return -1;
    }

    fseek(fp, 0, SEEK_SET);

    int32_t fileSize = ftell(fp);

    // uint8_t str[] = "\n";
    // for (int i = 0; i < 2; i++)
    // {
    //     printf("%02x ", str[i]);
    // }
    // printf("\n");

    // 上一次处理的数据多余部分
    uint8_t *otherData = NULL;
    int32_t otherDataLen = 0, readLen = 0;
    do
    {

        uint8_t *buf = (uint8_t *)malloc(BLOCK_SIZE);
        if (buf == NULL)
        {
            printf("malloc failed\n");
            break;
        }
        memset(buf, 0, BLOCK_SIZE);

        // 重新计算读取大小
        readLen = BLOCK_SIZE - otherDataLen;
        int32_t readSize = fread(&buf[otherDataLen], 1, readLen, fp);
        if (readSize <= 0 && otherDataLen == 0)
        {
            printf("read file failed\n");
            break;
        }

        printf("new section readSize %d  readLen %d otherDataLen %d -> {%#x}\n", readSize, readLen, otherDataLen, buf[otherDataLen]);

        if (otherDataLen != 0)
        {
            // 拷贝数据
            memcpy(buf, otherData, otherDataLen);
            // 释放
            if (otherData != NULL)
            {
                free(otherData);
                otherData = NULL;
            }
        }

        // 解析数据
        if (getDataLineCount(buf, readSize + otherDataLen, &otherDataLen) < 0)
        {
            printf("getDataLineCount failed\n");
            break;
        }

        // 处理多余的数据
        if (otherDataLen < readSize)
        {
            if (otherData != NULL)
            {
                free(otherData);
                otherData = NULL;
            }

            // 还有最后一部分数据待处理
            otherData = (uint8_t *)malloc(readSize - otherDataLen + 5);
            if (otherData == NULL)
            {
                printf("malloc failed\n");
                break;
            }
            memset(otherData, 0, readSize - otherDataLen + 5);
            memcpy(otherData, buf + otherDataLen, readSize - otherDataLen);

            // 多余数据长度
            otherDataLen = readSize - otherDataLen;
        }
        else
        {
            // 全部处理完毕
            otherDataLen = 0;
        }

        // 释放
        if (buf != NULL)
        {
            free(buf);
            buf = NULL;
        }

    } while (1);

    if (otherData != NULL)
    {
        free(otherData);
        otherData = NULL;
    }

    // 关闭文件
    if (fp != NULL)
    {
        fclose(fp);
        fp = NULL;
        printf("close file success\n");
    }

    return 0;
}
int main(int argc, char *argv[])
{
    printf("param count %d\n", argc);
    for (int i = 0; i < argc; i++)
    {
        printf("param[%d] %s\n", i, argv[i]);
    }

    if (argc < 2)
    {
        printf("%s", tips[0]);
        printf("%s", tips[1]);
        return 0;
    }

    if ((strcmp(argv[1], "help") == 0) || (strcmp(argv[1], "-h") == 0))
    {
        printf("%s", tips[0]);
        printf("%s", tips[1]);
        return 0;
    }

    parseIni(argv[1]);
    return 0;
}
